﻿#pragma once

#ifndef _FAN_FAN_
#include "resource.h"
#include "TimerUser.h"
#include "cstTime.h"
#include "IOCPSocket.h"
#include "SharePubInfo.h"
#include "PointerArray.cpp"

// CPubServer 对话框
#define PubServer_TITLE		L"公共信息私网同步服务"
#define PubInfoBroadcast_Port	9022

typedef struct _stDelegateStartParam
{
	CWnd *panel;
	CListenHostProcesser *processer;
	intptr_t maxNum;
} stDelegateStartParam;

class CIOCPSocketUIDelegate : public IIOCPSocketDelegate
{
public:
	CIOCPSocketUIDelegate(CIOCPListenSocket *listensocket);
	~CIOCPSocketUIDelegate();

	void StartService(LPVOID param = nullptr);
	void StopService(LPVOID param = nullptr);

	//from IIOCPSocketDelegate
	void logError(CIOCPSocket * socket, intptr_t errorCode, IOCP_OPERATOR oper = opNone, intptr_t sysErrorCode = 0) override;
	void logDebug(LPCSTR sFormat, ...) override;
	void ClientConnected(CAcceptSocket *socket) override
	{
		IIOCPSocketDelegate::ClientConnected(socket);
		InterlockedIncrement(&nowNum);
	}
	void ClientDisconnected(CAcceptSocket *socket) override
	{
		IIOCPSocketDelegate::ClientDisconnected(socket);
		InterlockedDecrement(&nowNum);
	}
	//from CUIDelegate
	bool IsRunning() override
	{
		return !stopping && IIOCPSocketDelegate::IsRunning();
	}

protected:
	bool stopping;
	vmpi_spin_lock cs_start;
	uintptr_t nowNum; intptr_t maxNum;

	virtual intptr_t Start_Service(LPVOID param) = 0;
	virtual bool Stop_Service(LPVOID param);
};

class CPubInfoClient;
typedef CPointerArray<CPubInfoClient*> CPubInfoClientArray;
class CPubInfoNode 
{
public:
	CPubInfoNode(TICK nowTk, CPubInfoClient *sender, const stPubInfoPacket *pPacket);
	bool SetPacket(CPubInfoClient *sender, const stPubInfoPacket *pPacket, bool newPacket);
	void RemoveClient(CPubInfoClient *pPctClt);
	void CheckSend();
	bool GetPubInfoTime(cst_tickTime_Page &t);
	bool GetPubInfoData(CPubInfoData &data);
	intptr_t GetClientNum();
	__forceinline unsigned short getInfoMark() const { return packet.infoMark; }

	TICK lastMsgTick;
protected:
	SRWLOCK cs_infoLock;
	const CPubInfoClient *pSender;
	stPubInfoPacket packet;
	cst_tickTime_Page m_HookTime;
	CPubInfoClientArray cltAry;
};
class CPubInfoNodeArray : public CPointerArray<CPubInfoNode*>
{
public:
	CPubInfoNodeArray(IUserDefineDelete<CPubInfoNode*> *deleter);
	void clear() override;
	bool CheckTimeout();
	const CPubInfoNode *SetPacket(TICK nowTk, CPubInfoClient *sender, const stPubInfoPacket *pPacket, 
		bool newPacket, bool &nodeAdded, bool &needSend);
	void RemoveClient(CPubInfoClient *pPctClt);
	void CheckSend(CPubInfoNode * pNode);
	bool SetCombo(CComboBox &combo, const CPubInfoNode *pDefault);

	SRWLOCK cs_lock;
};

#define	BPS_HEADMARK		0xc36d25fa
#pragma pack(push)
#pragma pack(1)
typedef struct _BPS_Packet
{
	unsigned int headMark;	//0xc36d25fa
	unsigned int packetSize;
	unsigned int ipNum;
	unsigned int crc;
#pragma warning(disable:4200)
	in_addr myIP[];
#pragma warning(default:4200)

	unsigned int getCRC() const
	{
		unsigned int v = headMark ^ packetSize^ipNum;
		for (intptr_t i = 0; i < ipNum; i++) v ^= myIP[i].s_addr;
		return v ^ 0x3f5a;
	}
} BPS_Packet;
#pragma pack(pop)

class CPubServer;
class CPubServerDelegate : public CIOCPSocketUIDelegate, public IPubInfoProc, public IUserDefineDelete<CPubInfoNode*>
{
public:
	CPubServerDelegate(CPubServer *owner);
	~CPubServerDelegate();
	static BPS_Packet *getMyPacket();

	//IIOCPSocketDelegate
	bool validPacket(const byte * data, intptr_t dataLength) override { return m_pubInfoProcesser.validPacket(data, dataLength); }
	size_t packetSize() override { return m_pubInfoProcesser.packetSize(); }
	//CIOCPSocketUIDelegate
	void ClientConnected(CAcceptSocket *socket) override;
	void ClientDisconnected(CAcceptSocket *socket) override;
	void DataRecved(CAcceptSocket *socket, const byte * data, intptr_t dataLength) override;
	void DataSended(CAcceptSocket *socket, LPVOID context) override;
	intptr_t ProcPacket(CAcceptSocket *socket, const byte * pRecv, intptr_t recvLen, LPVOID param) override
	{
		return m_pubInfoProcesser.ProcPacket(socket, pRecv, recvLen, param);
	}
	//IPubInfoProc
	void ProcPubInfo(CAcceptSocket *socket, const stPubInfoPacket *pPacket
#ifdef USE_OLD_PUBINFO_PACKET
		, const stPubInfoPacket_Old *pOldPacket
#endif
	) override;
	//IUserDefineDelete<CPubInfoNode*>
	void userDefineDelete(CPubInfoNode* rec) override;

	void CheckTimeout();
	CPubInfoNodeArray &NodeAry() { return nodeAry; }
	CPubInfoNodeArray &NodeBin() { return nodeBin; }
protected:
	intptr_t Start_Service(LPVOID param) override;
	bool Stop_Service(LPVOID param) override;
	CPubInfoClient * GetClient(CAcceptSocket *socket, bool readOnly);

	CPubServer *m_Owner;
	CPubInfoClient *m_pClt, *m_pCltEnd;
	uintptr_t workNum, clientNum;
	CPubInfoServerPacket m_pubInfoProcesser;
	CPubInfoNodeArray nodeAry, nodeBin;
	//广播接受线程
public:
	void broadcastThread();
	bool threadRunning;
protected:
	void setBroadcastSocket(SOCKET sock);
	HANDLE hBroadcastThread;
	bool stopThread;
	volatile SOCKET broadcastSock;
};


class CPubInfoClient
{
public:
	CPubInfoClient();
	~CPubInfoClient() { free(); }
public:
	SRWLOCK cs_client;
	CAcceptSocket *socket;
	TICK lastTick;

	void free();
	__forceinline void SetLastTick() { lastTick = TICK::Now(); }
	intptr_t CheckPubinfo(const stPubInfoPacket *pPacket
#ifdef USE_OLD_PUBINFO_PACKET
		, const stPubInfoPacket_Old *pOldPacket
#endif
	);
	void SendPubinfo(const stPubInfoPacket *pPacket);
	bool ClearPubinfo(const stPubInfoPacket *pPacket);
protected:
	int crcErrorTime;	//校验码错误次数
	stPubInfoPacket pubinfoPacket;
#ifdef USE_OLD_PUBINFO_PACKET
	stPubInfoPacket_Old oldPacket;
#endif
};


enum CloseOper { Prompt, Minimize, NoPrompt };
class CNowDisplay;
class CMinTimeDisplay;
class CFontFactory;
class CPubServer : public CDialogEx
{
	DECLARE_DYNAMIC(CPubServer)

public:
	CPubServer(bool startintray, CWnd* pParent = nullptr);   // 标准构造函数
	virtual ~CPubServer();

	// 对话框数据
	enum { IDD = IDD_PUBSERVER };
	BOOL OnInitDialog() override;
	BOOL DestroyWindow() override;
	void OnOK() override;
	void OnCancel() override;
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnClose();
	afx_msg LRESULT OnForceClose(WPARAM wParam, LPARAM lParam);
	afx_msg LRESULT OnShowMain(WPARAM wParam, LPARAM lParam);
	afx_msg void OnSelchangeAuction();
	afx_msg LRESULT OnRefreshCltNum(WPARAM wParam, LPARAM lParam);
	afx_msg LRESULT OnRefreshNodes(WPARAM wParam, LPARAM lParam);
	afx_msg LRESULT OnCheckSend(WPARAM wParam, LPARAM lParam);
	afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
	afx_msg void OnBnClickedExit();
	afx_msg void OnBnClickedHide();

	DECLARE_TIMER_EVENT()
protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

	DECLARE_MESSAGE_MAP()

	void toTray();
	void recoverTray(bool isClose);
	void DoSystime();
	void DoBidtime(const cst_tickTime_Page &t);
	const DFTick GetTimeDiff(const cst_tickTime_Page &t, bool doAdjust);
	void setCtrlShowTime(const CPlainTime &plain);
	void SetTimeClr(bool useSysTime, bool adjTimer);
	void ShowData();
	void ShowClientNum();

	HICON m_hIcon;
	CStatic m_Min;
	CStatic m_Max;
	CStatic m_CltNum;
	CComboBox m_Auction;
	CNowDisplay *m_NowDisplay;
	CMinTimeDisplay *m_MinTimeDisplay;

	DECLARE_TIMER()
	HUSERTIMER m_timerActive, m_Timer, m_adjTimer;
	bool startInTray, inTray, allowClose;
	CloseOper closeOper;
	CFontFactory *m_fFactory;
	vmpi_spin_lock cs_refresh;
	cst_tickTime_Now m_Now;		//当前时间
	bool m_useSysTime;
	int m_NonAdjTimes, m_WrongAdjTimes;
	CPubServerDelegate pubInfoDelegate;
	CPubInfoNode *m_pNode;		//只能在主线程使用，以避免发生被删除导致无效
	TICK tmoutChkTick;
	intptr_t m_clientNum;
};

#endif
